package arc;

import com.arc.message.Authentication;
import com.arc.level.Snapshot;
import com.arc.level.Snapshot;
import com.arc.message.ChangeRequest;
import com.arc.message.SerializableVector;
import com.arc.message.TickMessage;
import com.arc.state.AbstractState;
import com.arc.state.MessageState;
import com.jme3.app.SimpleApplication;
import com.jme3.network.Client;
import com.jme3.network.ClientStateListener;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import com.jme3.network.Server;
import com.jme3.network.serializing.Serializer;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Node;
import com.jme3.system.JmeContext;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;


public class ArcClient extends ArcBase implements ClientStateListener, MessageListener<Client> {    
    static final String version = "0.0.1";
    static final int    snapshotMemory = 3;
    Client myClient;
    public boolean isAuthenticated;
    ClientLevelState clientLevelState;

    public ArcClient()
    {
        Serializer.registerClass(Authentication.class);      
        Serializer.registerClass(MessageState.class);       
        Serializer.registerClass(AbstractState.class);
        Serializer.registerClass(TickMessage.class);
        Serializer.registerClass(Snapshot.class); 
        Serializer.registerClass(Snapshot.class); 
        Serializer.registerClass(ChangeRequest.class);   
        Serializer.registerClass(SerializableVector.class); 
        isAuthenticated = false;
    }
    
    @Override
    public void simpleInitApp() {
        super.simpleInitApp();
        clientLevelState = new ClientLevelState();
        getStateManager().attach(clientLevelState);
        
        try {
            myClient = Network.connectToServer("localhost", 6143);
            myClient.addClientStateListener(this);
            myClient.addMessageListener(this);
            myClient.start();
            System.out.println("Client started");
        } catch (IOException ex) {
            Logger.getLogger(ArcClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        flyCam.setMoveSpeed(100);
    }

    @Override
    public void simpleUpdate(float tpf) {       
       
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
    
    public void close(String msg)
    {
        if(myClient == null) return;
        
        if(myClient.isConnected())
        {
            myClient.close();
            System.out.println("[CLIENT]\t"+msg);
        }
    }
    
    @Override
    public void destroy()
    {
        close("Destroy");
        super.destroy();
    }

    public void clientConnected(Client c) {
        if(c == myClient)
        {
            Authentication msg = new Authentication(myClient.getVersion(), myClient.getGameName());
            msg.setReliable(true);
            //msg.getState().updateState(this, Type.Client, null);
            myClient.send(msg);
            System.out.println("[Client] Attempting to authenticate with server...");
        }
    }

    public void clientDisconnected(Client c, DisconnectInfo info) {
        
    }

    public void messageReceived(Client source, Message msg) {
        if(msg instanceof Authentication)
        {
            Authentication shake = (Authentication)msg;
            if(shake.authenticated)
            {
                System.out.println("[Client] Authentication successful.");
                isAuthenticated = true;
            }
        }
        
        if(msg instanceof TickMessage)
        {
            final TickMessage tick = (TickMessage)msg;
            if(tick.isReliable())
                System.out.println("[Client] Initialize");
            
            clientLevelState.pushSnapshot(tick.getSnapshot());
        }
    }
}
